package com.coszero.utils.file

import android.content.res.AssetManager
import android.os.Build
import android.os.Environment
import android.util.Log
import com.coszero.utils.utils.LogX
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.FilenameFilter
import java.io.IOException
import java.io.InputStream
import java.nio.file.FileSystemException
import java.nio.file.Files
import java.nio.file.StandardCopyOption

/**
 * Desc： 文件控制
 * 通常文件控件的操作有 复制 移动 删除 新增
 *
 * @author xmqian
 * Email:xmqian93@163.com
 * Date: 2020/10/12 0012 14:52
 * @version 1
 */
object FileControl {
    private const val TAG = "fileControl"

    // <editor-fold desc="文件复制" defaultstate="collapsed">
    /**
     * 复制文件
     *
     * @param source 输入文件
     * @param target 输出文件
     */
    @JvmStatic
    fun copy(source: File?, target: File?) {
        var fileInputStream: FileInputStream? = null
        var fileOutputStream: FileOutputStream? = null
        try {
            fileInputStream = FileInputStream(source)
            fileOutputStream = FileOutputStream(target)
            val buffer = ByteArray(1024)
            while (fileInputStream.read(buffer) > 0) {
                fileOutputStream.write(buffer)
            }
        } catch (e: Exception) {
            e.printStackTrace()
        } finally {
            try {
                fileInputStream?.close()
                fileOutputStream?.close()
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }
    }

    /**
     * 复制文件
     *
     * @param filename 文件名
     * @param bytes 数据
     */
    fun copy(filename: String, bytes: ByteArray?) {
        try {
            //如果手机已插入sd卡,且app具有读写sd卡的权限
            if (Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED) {
                var output: FileOutputStream? = null
                output = FileOutputStream(filename)
                output.write(bytes)
                Log.i("FileUtils", "copy: success$filename")
                output.close()
            } else {
                Log.i("FileUtils", "copy:fail, $filename")
            }
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }

    /**
     * 从asset文件夹中复制文件
     *
     * @param assets Context.getAssets()
     * @param source assets文件夹中文件的路径或文件名称
     * @param dest 复制文件的目标路径,绝对路径,包含文件名
     * @param isCover 是否覆盖 true覆盖 false如果已有就不进行复制
     * @throws IOException IOException
     * @permission 读写
     */
    @JvmStatic
    @JvmOverloads
    @Throws(IOException::class)
    fun copy(assets: AssetManager, source: String, dest: String, isCover: Boolean = true) {
        val file = File(dest)
        if (isCover || !file.exists()) {
            var `is`: InputStream? = null
            var fos: FileOutputStream? = null
            try {
                `is` = assets.open(source)
                val path = dest
                fos = FileOutputStream(path)
                val buffer = ByteArray(1024)
                var size = 0
                while ((`is`.read(buffer, 0, 1024).also { size = it }) >= 0) {
                    fos.write(buffer, 0, size)
                }
            } finally {
                if (fos != null) {
                    try {
                        fos.close()
                    } finally {
                        `is`?.close()
                    }
                }
            }
        }
    }


    //</editor-fold>
    // <editor-fold desc="文件删除" defaultstate="collapsed">
    /**
     * 删除目录下的所有文件及文件夹
     *
     * @param root 目录
     */
    fun deleteAllFiles(root: File) {
        val files = root.listFiles()
        if (files != null) for (f in files) {
            if (f.isDirectory) { // 判断是否为文件夹
                deleteAllFiles(f)
                try {
                    f.delete()
                } catch (e: Exception) {
                }
            } else {
                if (f.exists()) { // 判断是否存在
                    deleteAllFiles(f)
                    try {
                        f.delete()
                    } catch (e: Exception) {
                    }
                }
            }
        }
    }

    //</editor-fold>
    // <editor-fold desc="文件新增" defaultstate="collapsed">
    /**
     * 判断是否有该文件夹,没有则创建文件夹
     *
     * @param dirPath 文件路径
     * @return 是否有该文件路径
     */
    fun makeDir(dirPath: String): Boolean {
        return FileDirPathUtils.makeDir(dirPath)
    }


    //</editor-fold>
    // <editor-fold desc="文件移动" defaultstate="collapsed">
    /**
     * 移动文件到指定文件夹
     *
     * @param fromFile 需要被移动的目标文件
     * @param toDir 移动的指定文件夹
     * @return 是否移动成功
     */
    fun moveFileToDir(fromFile: File, toDir: File): Boolean {
        if (!toDir.exists()) {
            toDir.mkdirs()
        }
        return move(fromFile, toDir)
    }

    /**
     * 移动文件
     *
     * @param fromFile 需要被移动的目标文件
     * @param toFile 移动到指定文件夹,此为文件对象,不是文件夹,如果是文件夹必须要该文件夹先存在
     * @return 是否移动成功
     */
    fun move(fromFile: File, toFile: File): Boolean {
        //判断被移动的文件是否存在
        var toFile = toFile
        if (!fromFile.exists()) {
            throw NullPointerException("需要移动的目标文件不存在")
        }
        //fromFile是文件,toFile是文件夹,将toFile拼接成文件
        if (toFile.exists() && toFile.isDirectory && fromFile.isFile) {
            toFile = File(toFile.absolutePath + File.separator + fromFile.name)
        }
        //创建文件夹
        if (!toFile.parentFile.exists()) {
            toFile.parentFile.mkdirs()
        }
        //8.0才可以使用jdk1.8的方法
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val fromPath = fromFile.toPath()
            val toPath = toFile.toPath()
            if (toFile.exists() && toFile.isDirectory) {
                LogX.i(TAG, "moveData copyDir")
                return moveDirs(fromFile, toFile)
            } else {
                try {
                    LogX.i(TAG, "moveData Files.move")
                    Files.move(fromPath, toPath, StandardCopyOption.ATOMIC_MOVE)
                    return true
                } catch (e: FileSystemException) {
                    //toFile没有对应文件夹会报此错
                    e.printStackTrace()
                } catch (e: IOException) {
                    e.printStackTrace()
                }
            }
        } else {
            if (toFile.exists() && toFile.isDirectory) {
                LogX.i(TAG, "moveData copyDir")
                return moveDirs(fromFile, toFile)
            } else {
                val result = fromFile.renameTo(toFile)
                LogX.i(TAG, "moveData renameTo result $result")
                return result
            }
        }
        return false
    }

    /**
     * 移动文件夹
     *
     * @param fromDir 需要被移动的目标文件夹
     * @param toDir 移动到指定文件夹目录
     * @return 是否移动成功
     */
    fun moveDirs(fromDir: File?, toDir: File?): Boolean {
        var moveDirFiles = true
        if (fromDir == null || toDir == null) {
            return false
        }

        if (!toDir.exists()) {
            toDir.mkdirs()
        }

        val sourceS = fromDir.path
        val targetS = toDir.path
        val paths = fromDir.list()

        for (tmp in paths!!) {
            val tmpFile = File(sourceS + File.separator + tmp)
            val newFile = File(targetS + File.separator + tmp)
            moveDirFiles = if (tmpFile.isDirectory) {
                moveDirs(tmpFile, newFile)
            } else {
                move(tmpFile, newFile)
            }
        }
        return moveDirFiles
    }

    //</editor-fold>
    // <editor-fold desc="文件查找" defaultstate="collapsed">
    /**
     * 获取当前目录下所有的文件
     *
     * @param dirPath 文件夹路径
     * @param suffix 指定的后缀名,如果为空，返回所有类型文件 如:.jpg,.mp4
     */
    fun getFiles(dirPath: String, vararg suffix: String): Array<File>? {
        val suffixArray: Array<String> = suffix
        val dir = File(dirPath)
        if (!dir.exists()) {
            LogX.w(TAG, String.format("路径 \n%s\n 不存在", dirPath))
            return null
        }
        if (!dir.isDirectory) {
            LogX.w(TAG, String.format("路径 \n%s\n 不是文件夹", dirPath))
            return null
        }
        val files = dir.listFiles(FilenameFilter { dir, name ->
            if (suffixArray == null || suffixArray.size == 0) {
                return@FilenameFilter true
            }
            //循环比对所有后缀名，符合就返回
            for (i in suffixArray.indices) {
                if (name.endsWith(suffixArray[i])) {
                    return@FilenameFilter true
                }
            }
            false
        })
        return files
    }

    /**
     * @param dirPath 文件夹地址
     * @return 文件夹下的所有文件, 不区分后缀类型
     */
    fun getFiles(dirPath: String): Array<File>? {
        val suffix = arrayOf<String>()
        return getFiles(dirPath, *suffix)
    } //</editor-fold>
}
